package com.dragon.english_practice_back.service.impl;

import cn.hutool.core.util.StrUtil;
import com.dragon.english_practice_back.service.AsyncRedisUpdateService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;


@Service
@EnableAsync
@AllArgsConstructor
@Slf4j
public class AsyncRedisUpdateServiceImpl implements AsyncRedisUpdateService {
    RedissonClient redissonClient;

    /**
     更新数个元素的熟练度
     redisTemplate是redis模板对象
     redisListKey是存储在redis中的list的key
     redisLock是redisson的锁的key
     index是list的下标
     mapKey是list中的map的key
     changeScope是改变的程度,比如+1,-1
     **/
    @Override
    @Async
    public void updateProficiency(RedisTemplate<String, Map<String, Object>> redisTemplate,
                                  String redisListKey,
                                  String redisLock,
                                  List<Integer> index,
                                  String mapKey,
                                  int changeScope) {
        // 数据校验
        if (redisTemplate == null
        || StrUtil.isEmpty(redisListKey)
        || StrUtil.isEmpty(redisLock)
        || index == null
        || index.isEmpty()
        || StrUtil.isEmpty(mapKey)
        || changeScope == 0) {
            return;
        }


        // 获取锁
        RLock lock = redissonClient.getLock(redisLock);
        try{
            log.info("tryLock for redisLock: {}", redisLock);
            // 尝试加锁（等待60秒，最大锁定300秒）
            if (lock!= null && lock.tryLock(60, 300, TimeUnit.SECONDS)) {
                // redis数组长度
                long redisListSize = redisTemplate.opsForList().size(redisListKey);
                // 遍历index,更新熟练度
                for (Integer i : index) {
                    // 检查index是否越界
                    if (i < 0 || i >= redisListSize) {
                        continue;
                    }
                    // 获取数组中的map
                    Map<String, Object> map = redisTemplate.opsForList().index(redisListKey, i);
                    if (map != null && map.containsKey(mapKey)) {
                        int proficiency = Integer.parseInt(map.get(mapKey).toString());
                        proficiency += changeScope;
                        // 将proficiency的范围限制在0-100
                        if (proficiency < 0) {
                            proficiency = 0;
                        }
                        else if (proficiency > 100) {
                            proficiency = 100;
                        }
                        map.put(mapKey, proficiency);
                        redisTemplate.opsForList().set(redisListKey, i, map);
                    }
                }

            }
            // 加锁超时
            else {
                log.error("数据更新失败, 加锁超时, redisListKey: {}, redisLock: {}, index: {}, mapKey: {}, changeScope: {}", redisListKey, redisLock, index, mapKey, changeScope);

            }

        }
        catch (Exception e){
            log.error(e.getMessage());
        }
        finally {
            if (lock != null && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    @Override
    @Async
    public void ClearSchedule(@NotNull RedisTemplate<String, Map<String, Object>> redisTemplate,
                                       @NotNull String redisListKey,
                                       @NotNull String redisLock) {
        // 创建锁
        RLock lock = redissonClient.getLock(redisLock);
        try{
            log.info("tryLock for redisLock: {}", redisLock);
            // 尝试加锁（等待60秒，最大锁定300秒）
            if (lock!= null && lock.tryLock(60, 300, TimeUnit.SECONDS)) {
                redisTemplate.delete(redisListKey);
                log.info("数据清除成功, redisListKey: {}", redisListKey);
            }
        }
        catch (Exception e){
            log.error(e.getMessage());
        }
        finally {
            if (lock!= null && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }

    }
}
